package com.mate.cloud.auth.config;

import com.mate.cloud.auth.handler.CustomAuthenticationSuccessHandler;
import com.mate.cloud.auth.handler.LoggingAuthenticationFailureHandler;
import com.mate.cloud.auth.service.UserService;
import com.mate.cloud.auth.service.impl.CustomUserDetailsService;
import jakarta.annotation.Resource;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.logout.LogoutHandler;
import org.springframework.security.web.authentication.logout.LogoutSuccessHandler;
import org.springframework.security.web.authentication.rememberme.JdbcTokenRepositoryImpl;
import org.springframework.security.web.authentication.rememberme.PersistentTokenRepository;

import javax.sql.DataSource;
import java.io.IOException;

/**
 * Spring Security 配置类
 *
 * @author: MI
 * @email: 448341911@qq.com
 * @createTime: 2024/6/14 18:11
 * @updateUser: MI
 * @updateTime: 2024/6/14 18:11
 * @updateRemark: 修改内容
 * @version: v1.0
 */
@Slf4j
@Configuration
public class AuthorizationServerConfig {
    @Resource
    private UserService userService;

    @Resource
    private DataSource dataSource;

    // 配置自定义的 UserDetailsService
    @Bean
    public UserDetailsService userDetailsService() {
        log.info("userDetailsService()");
        return new CustomUserDetailsService(this.userService);
    }


    // 持久化对象
    @Bean
    public PersistentTokenRepository getPersistentTokenRepository() {
        JdbcTokenRepositoryImpl jdbcTokenRepositoryImpl = new JdbcTokenRepositoryImpl();
        jdbcTokenRepositoryImpl.setDataSource(dataSource);
        // 自动建表，第一次启动时需要，第二次启动时注释掉
        jdbcTokenRepositoryImpl.setCreateTableOnStartup(false);
        return jdbcTokenRepositoryImpl;
    }

    //滤器链的相关设置
    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        log.info("securityFilterChain()");
        // csrfCustomizer.ignoringRequestMatchers(*) 表示所有请求地址都不使用 csrf
        http.csrf(csrfCustomizer -> csrfCustomizer.ignoringRequestMatchers("*"))
                // 授权请求配置（新语法）
                .authorizeHttpRequests(authorize -> authorize
                        // 配置登陆失败页面访问不需要鉴权
                        .anyRequest().authenticated())
                // 你还可以根据需求进行更多的配置，如自定义登录页面的 URL、登录成功或失败的处理逻辑等。
                .formLogin(e -> e.loginProcessingUrl("/login") // 配置处理登陆请求到地址
                        // 自定义登陆页面地址
                        .loginPage("/login")
                        .usernameParameter("userName") // 自定义用户名参数名称
                        .passwordParameter("passWord") // 自定义密码参数名称
//                        .loginProcessingUrl("/login")
                        .defaultSuccessUrl("/index", true)
                        // // 自定义登陆成功页面
                        .defaultSuccessUrl("/success", true)
                        // 自定义登录成功逻辑
                        .successHandler(new CustomAuthenticationSuccessHandler())
                        // 自定义登陆失败逻辑【快看这里】
//                        .failureHandler(new CustomAuthenticationFailureHandler2())
                        .failureHandler(new LoggingAuthenticationFailureHandler())
                        .permitAll())
                // 处理退出的地址
                .logout(e ->e.logoutUrl("/logout")
                        // 删除 remember-me Cookie（看这里）
                        .deleteCookies("JSESSIONID", "remember-me")
                        // 添加自定义退出逻辑
                        .addLogoutHandler((request, response, authentication) -> {
                            System.out.println(authentication.getName() + " 已退出");
                            // 清理自定义缓存或资源
                            // 其他操作
                        })
                        // 自定义退出成功处理逻辑
                        .logoutSuccessHandler((request, response, authentication) -> {
                            // 登录成功后重定向到 /login?logout=success 页面
                            response.sendRedirect("/login?logout=success");
                        })
                )
                // remember me
                .rememberMe(rememberMeCustomizer -> rememberMeCustomizer
                        .userDetailsService(userDetailsService()) //登录逻辑交给哪个对象
                        //持久层对象
                        .tokenRepository(getPersistentTokenRepository())
                        // 单位秒
                        .tokenValiditySeconds(120)
                );

        return http.build();
    }

    // 配置密码编码器
    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

}
